package movieGandalf.GUI;



import movieGandalf.BL.ObjectsMYSQLBL;
import movieGandalf.common.Log;
import movieGandalf.database.MovieTools;
import movieGandalf.logicGuiConnection.User;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class GUIManager {
	private static final int SHELL_WIDTH = 900;
	private static final int SHELL_HEIGHT = 600;
	
	
	private static Label message;
	private static Thread statusThread;
	private static Composite statusBar;
	private static String statusMessage;
	
	
	static Display display;
	static Shell shell;
	private static Composite currentPage;

   
    public static void main(String[] args) {

    	display = Display.getDefault();
    	shell = new Shell(SWT.TITLE | SWT.CLOSE | SWT.MIN);
    	    
    	shell.setImage(new Image(display,
    			GUIManager.class.getResourceAsStream(
    					"/images/ic_gandalf.png")));
    	shell.setText("Movie Gandalf");
    	shell.setSize(SHELL_WIDTH, SHELL_HEIGHT);
    	center(shell);		
		shell.setLayout(new FormLayout());
		
		try {
	    	//using  ObjectsBL Class to init connection to sql server
	    	MovieTools.init();
	    	new ObjectsMYSQLBL();
		} catch (Exception e) {
			fatalError(e, "Could not initialize Application - See log file");
			return;
		}
		
		createStatusBar();
		
		displayLogin();
		
		
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		display.dispose();
		MovieTools.close();
    }

    
    
	/* Creates the status bar that appears at all times in bottom of the application */
	private static void createStatusBar() {
		statusBar = new Composite(shell, SWT.BORDER);
		FormData fd_statusBar = new FormData();
		fd_statusBar.bottom = new FormAttachment(100);
		fd_statusBar.left = new FormAttachment(0);
		fd_statusBar.right = new FormAttachment(100);
		statusBar.setLayoutData(fd_statusBar);
		statusBar.setBackground(SWTResourceManager.getColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND));
		statusBar.setLayout(new RowLayout(SWT.HORIZONTAL));
		
		message = new Label(statusBar, SWT.NONE);
		message.setFont(SWTResourceManager.getFont("Lucida Grande", 12, SWT.BOLD));
		message.setLayoutData(new RowData(SWT.DEFAULT, 20));
		statusMessage = "";
		sendStatus(statusMessage, StatusEnum.REGULAR);
	}

    public static void center(Shell shell) {

        Rectangle bds = shell.getDisplay().getBounds();

        Point p = shell.getSize();

        int nLeft = (bds.width - p.x) / 2;
        int nTop = (bds.height - p.y) / 2;

        shell.setBounds(nLeft, nTop, p.x, p.y);
    }
    
	
	/* Function that brings the application to the login state */
	static void displayLogin() {
		for (Shell curShell : shell.getShells()) {
			curShell.dispose();
		}
		
		if (currentPage != null && !currentPage.isDisposed()) {
			currentPage.dispose();
		}
		
		currentPage = new LoginPage(shell, SWT.NONE);
		setCurrentPageLayoutData();
		
		shell.layout();
	}
	
	/* This function is called in order to login to the system with the given character */
	static void login(User u) {
		currentPage.dispose();
		currentPage = new MovieGandalfGUI(shell, SWT.NONE, u);
		setCurrentPageLayoutData();
		
		sendStatus("You are logged in as " + u.getUsername(), StatusEnum.REGULAR);
		shell.layout();
	}
	
	private static void setCurrentPageLayoutData() {
		FormData fd_currentPage = new FormData();
		fd_currentPage.top = new FormAttachment(0);
		fd_currentPage.left = new FormAttachment(0);
		fd_currentPage.right = new FormAttachment(100);
		fd_currentPage.bottom = new FormAttachment(100);
		
		currentPage.setLayoutData(fd_currentPage);
	}

	/* This function is used to send a runnable code to be executed in the main thread (typically code that deals with GUI) */
	static void sendToMainThread(Runnable runnable) {
		if (!display.isDisposed() && display != null)
			display.asyncExec(runnable);
	}
	
	/* The different types of messages that can be sent to the status bar */
	enum StatusEnum {
		ERROR(SWT.COLOR_RED),
		INFORM(SWT.COLOR_DARK_GREEN),
		REGULAR(SWT.COLOR_BLACK);
		
		final int swtColor;
		
		StatusEnum(int swtColor) {
			this.swtColor = swtColor;
		}
	}
	
	/* This function is used to send a message to the status bar */
	static void sendStatus(final String msg, final StatusEnum type) {
		if (display.isDisposed()) {
			return;
		}
		
		if (display.getThread() != Thread.currentThread()) {
			Runnable run = new Runnable() {

				@Override
				public void run() {
					GUIManager.sendStatus(msg, type);
				}
			};
			sendToMainThread(run);
			return;
		}
		
		if (message.isDisposed())
			return;
		
		if ((statusThread != null) && statusThread.isAlive()) {
			statusThread.interrupt();
		}
		
		message.setForeground(SWTResourceManager.getColor(type.swtColor));
		message.setText(msg);
		message.setSize(message.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
		
		if (type != StatusEnum.REGULAR) {
			statusThread = new StatusThread();
			statusThread.start();
		} else {
			statusMessage = msg;
		}
	}
	
	/* This class extends Thread and is used in order to return the default status string after a constant amount of time */
	private static class StatusThread extends Thread {
		
		private static int timer = 5;
		
		public void run() {
			try {
				Thread.sleep(timer * 1000);
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
				return;
			}
			GUIManager.sendStatus(statusMessage, StatusEnum.REGULAR);				
		}

	}
	/* These functions are called when an error, with which the application cannot continue to run, occurred */
	static void fatalError(Exception exp, String msg) {
		Log.getInstance().WriteMessage(exp);
		fatalError(msg);
	}
	
	static void fatalError (Exception exp) {
		Log.getInstance().WriteMessage(exp);
		fatalError(exp.getMessage());
	}
	
	static synchronized void fatalError(final String msg) {
		
		if (display.isDisposed()) {
			return;
		}
		
		if (display.getThread() != Thread.currentThread()) {
			Runnable run = new Runnable() {

				@Override
				public void run() {
					GUIManager.fatalError(msg);
				}
			};
			sendToMainThread(run);
			return;
		}
		
		if (shell.isDisposed()) {
			return;
		}
		
		final Shell errorDialog = new Shell(shell,
				(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL) & ~SWT.CLOSE);
		errorDialog.setText("Fatal Error");
		errorDialog.setLayout(new FormLayout());
		
		Label firstLabel = new Label(errorDialog, SWT.NONE);
		FormData fd_firstLabel = new FormData();
		fd_firstLabel.top = new FormAttachment(0, 5);
		fd_firstLabel.right = new FormAttachment(100, -5);
		fd_firstLabel.left = new FormAttachment(0,2);
		firstLabel.setLayoutData(fd_firstLabel);
		firstLabel.setAlignment(SWT.LEFT);
		firstLabel.setText("Fatal Error! Application will close itself.");
		
		Label secondLabel = new Label(errorDialog, SWT.NONE);
		FormData fd_secondLabel = new FormData();
		fd_secondLabel.top = new FormAttachment(firstLabel, 0, SWT.BOTTOM);
		fd_secondLabel.right = new FormAttachment(100, -5);
		fd_secondLabel.left = new FormAttachment(0,2);
		secondLabel.setLayoutData(fd_secondLabel);
		secondLabel.setAlignment(SWT.LEFT);
		secondLabel.setText(msg);
		
		Button exitButton = new Button(errorDialog, SWT.PUSH);
		exitButton.setText("Bye Bye...");
		exitButton.pack();
		FormData fd_exitButton = new FormData();
		fd_exitButton.top = new FormAttachment(secondLabel, 2, SWT.BOTTOM);
		fd_exitButton.left = new FormAttachment(50, -exitButton.getSize().x / 2);
		exitButton.setLayoutData(fd_exitButton);
		
		exitButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				errorDialog.dispose();
			}
		});
		
		errorDialog.open();
		errorDialog.layout();
		errorDialog.pack();

		while (!errorDialog.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		MovieTools.close();
		shell.close();
	}
}
